/*
 * @Author: Wangjun
 * @Date: 2023-04-13 11:11:47
 * @LastEditTime: 2023-12-28 18:44:14
 * @LastEditors: wangjun haodreams@163.com
 * @Description:
 * @FilePath: \libs\expr\function.go
 * hnxr
 */
package expr

import (
	"bytes"
	"errors"
	"strconv"
	"strings"
	"time"
)

/**
 * @description: if 函数接收三个参数， 第一个条件
 * @param {...float64} x
 * @return {*}
 */
func IF(x ...float64) (float64, error) {
	if len(x) != 3 {
		err := errors.New("参数错误,If 函数的参数必须是3个")
		return 0, err
	}
	if int(x[0]) != 0 {
		return x[1], nil
	}
	return x[2], nil
}

/**
 * @description: 最大值
 * @param {...float64} x
 * @return {*}
 */
func Max(x ...float64) (float64, error) {
	if len(x) == 0 {
		err := errors.New("参数错误,MAX函数的参数必须至少是1个")
		return 0, err
	}
	max := x[0]
	for _, v := range x {
		if max < v {
			max = v
		}
	}
	return max, nil
}

/**
 * @description: 最小值
 * @param {...float64} x
 * @return {*}
 */
func Min(x ...float64) (float64, error) {
	if len(x) == 0 {
		err := errors.New("参数错误,MIN函数的参数必须至少是1个")
		return 0, err
	}
	min := x[0]
	for _, v := range x {
		if min > v {
			min = v
		}
	}
	return min, nil
}

/**
 * @description: 求和
 * @param {...float64} x
 * @return {*}
 */
func Sum(x ...float64) (float64, error) {
	if len(x) == 0 {
		err := errors.New("参数错误,SUM函数的参数必须至少是1个")
		return 0, err
	}
	sum := x[0]
	for _, v := range x {
		sum += v
	}
	return sum, nil
}

/**
 * @description: 求平均值
 * @param {...float64} x
 * @return {*}
 */
func Avg(x ...float64) (float64, error) {
	sum, err := Sum(x...)
	if err != nil {
		return sum, err
	}
	return sum / float64(len(x)), nil
}

/**
 * @description: 当前时间
 * @param {...float64} x
 * @return {*}
 */
func Now(x ...float64) (float64, error) {
	return float64(time.Now().Unix()), nil
}

/**
 * @description: 当前日期
 * @param {...float64} x
 * @return {*}
 */
func Date(x ...float64) (float64, error) {
	now := time.Now().Format("20060102")
	d, _ := strconv.Atoi(now)
	return float64(d), nil
}

/**
 * @description: 当前时间
 * @param {...float64} x
 * @return {*}
 */
func Time(x ...float64) (float64, error) {
	now := time.Now().Format("150405")
	t, _ := strconv.Atoi(now)
	return float64(t), nil
}

/**
 * @description: 第一个数据是否和后面的数据相等
 * @param {...float64} x
 * @return {*}
 */
func In(x ...float64) (float64, error) {
	n := len(x)
	if n == 0 {
		return 0, nil
	}
	v := x[0]
	for i := 1; i < n; i++ {
		if v == x[i] {
			return 1, nil
		}
	}
	return 0, nil
}

func isLetter(ch byte) bool {
	return ('a' <= lower(ch) && lower(ch) <= 'z') || ('0' <= ch && ch <= '9')
}
func lower(ch byte) byte { return ('a' - 'A') | ch }

/**
 * @description: x in (a,b,c) 转为 IN(x,a,b,c)
 * @param {string} s
 * @return {*}
 */
func ConvertIn(s string, buf *bytes.Buffer) string {
	if s == "" {
		return ""
	}
	data := []byte(s)
	n := len(s)

	idx := strings.Index(s, "in")
	if idx < 0 {
		idx = strings.Index(s, "IN")
	}
	if idx > 0 && idx < (n-3) {
		if (data[idx-1] == ' ' || data[idx-1] == '\t') && (data[idx+2] == ' ' || data[idx+2] == '\t' || data[idx+2] == '(') {
			es := 0
			key := ""
			keyb := 0
			keye := 0
			ok := false
			if buf == nil {
				buf = bytes.NewBuffer(nil)
			}
			for i := idx + 2; i < n; i++ {
				if data[i] == ' ' {
					continue
				}
				if data[i] == '(' {
					es = i + 1
					ok = true
					break
				}
			}
			if ok {
				for i := idx; i >= 0; i-- {
					if data[i] == ' ' {
						continue
					}
					if isLetter(data[i]) {
						if keye == 0 {
							keye = i
						}
						continue
					} else {
						keyb = i + 1
						break
					}
				}
				key = strings.TrimSpace(s[keyb:keye])
				key += ","
				for i := keyb; i < es; i++ {
					data[i] = ' '
				}
				data[keyb] = 'I'
				data[keyb+1] = 'N'
				data[keyb+2] = '('
				copy(data[keyb+3:], []byte(key))

				//s = string(data[:es]) + ConvertIn(s[es:])
				buf.Write(data[:es])
				ConvertIn(s[es:], buf)
				return buf.String()
			}
		}
	}
	if buf != nil {
		buf.WriteString(s)
		return ""
	}
	return s
}
